#include "common.h"

uint32 ghtonl(uint32 x) {
	union {
		uint32 result;
		uint8 result_array[4];
	};
	result_array[0] = static_cast<uint8>(x >> 24);
	result_array[1] = static_cast<uint8>((x >> 16) & 0xFF);
	result_array[2] = static_cast<uint8>((x >> 8) & 0xFF);
	result_array[3] = static_cast<uint8>(x & 0xFF);
	return result;
}

namespace io {

	// ----------------------------------------------------------------------
	// NoLocaleStrtod()
	//   This code will make you cry.
	// ----------------------------------------------------------------------

	namespace {

		// Returns a string identical to *input except that the character pointed to
		// by radix_pos (which should be '.') is replaced with the locale-specific
		// radix character.
		string LocalizeRadix(const char* input, const char* radix_pos) {
			// Determine the locale-specific radix character by calling sprintf() to
			// print the number 1.5, then stripping off the digits.  As far as I can
			// tell, this is the only portable, thread-safe way to get the C library
			// to divuldge the locale's radix character.  No, localeconv() is NOT
			// thread-safe.
			char temp[16];
			int size = sprintf(temp, "%.1f", 1.5);
			GOOGLE_CHECK_EQ(temp[0], '1');
			GOOGLE_CHECK_EQ(temp[size - 1], '5');
			GOOGLE_CHECK_LE(size, 6);

			// Now replace the '.' in the input with it.
			string result;
			result.reserve(strlen(input) + size - 3);
			result.append(input, radix_pos);
			result.append(temp + 1, size - 2);
			result.append(radix_pos + 1);
			return result;
		}

	}  // namespace

	double NoLocaleStrtod(const char* text, char** original_endptr) {
		// We cannot simply set the locale to "C" temporarily with setlocale()
		// as this is not thread-safe.  Instead, we try to parse in the current
		// locale first.  If parsing stops at a '.' character, then this is a
		// pretty good hint that we're actually in some other locale in which
		// '.' is not the radix character.

		char* temp_endptr;
		double result = strtod(text, &temp_endptr);
		if (original_endptr != NULL) *original_endptr = temp_endptr;
		if (*temp_endptr != '.') return result;

		// Parsing halted on a '.'.  Perhaps we're in a different locale?  Let's
		// try to replace the '.' with a locale-specific radix character and
		// try again.
		string localized = LocalizeRadix(text, temp_endptr);
		const char* localized_cstr = localized.c_str();
		char* localized_endptr;
		result = strtod(localized_cstr, &localized_endptr);
		if ((localized_endptr - localized_cstr) >
			(temp_endptr - text)) {
			// This attempt got further, so replacing the decimal must have helped.
			// Update original_endptr to point at the right location.
			if (original_endptr != NULL) {
				// size_diff is non-zero if the localized radix has multiple bytes.
				int size_diff = localized.size() - strlen(text);
				// const_cast is necessary to match the strtod() interface.
				*original_endptr = const_cast<char*>(
					text + (localized_endptr - localized_cstr - size_diff));
			}
		}

		return result;
	}

	float SafeDoubleToFloat(double value) {
		if (value > std::numeric_limits<float>::max()) {
			return std::numeric_limits<float>::infinity();
		}
		else if (value < -std::numeric_limits<float>::max()) {
			return -std::numeric_limits<float>::infinity();
		}
		else {
			return static_cast<float>(value);
		}
	}

}  // namespace io